import gc
import logging
import inspect
import sys
import os
import unittest
import atexit
from pathlib import Path
from datetime import datetime
from logging.handlers import RotatingFileHandler

from config.settings import get_config


class Logger:
    _loggers = {}  # 单例缓存池
    _generated_logs = []  # 记录所有生成的日志文件路径

    def __new__(cls, name=None, device_type=None):
        # 获取配置参数优先
        config = get_config(device_type)

        # 生成时间戳
        timestamp = datetime.now().strftime("%m%d_%H%M%S")

        # 智能检测脚本名称
        if name is None:
            name = cls._detect_root_script() or "unknown_script"
            name = name.replace("_jb_unittest_runner", "")  # 过滤IDE运行器

        # 构建最终日志名称
        logger_name = f"{name}_{device_type}_{timestamp}" if device_type else f"{name}_{timestamp}"

        # 单例模式实现
        cache_key = f"{logger_name}_{device_type or ''}"
        if cache_key not in cls._loggers:
            instance = super().__new__(cls)
            instance.device_type = device_type
            instance.config = config  # 直接使用已获取的配置
            instance._initialize(logger_name)
            cls._loggers[cache_key] = instance
        return cls._loggers[cache_key]

    def _initialize(self, logger_name):
        self.logger = logging.getLogger(logger_name)
        if not self.logger.handlers:  # 防止重复初始化
            self.logger.setLevel(self.config.log_level)
            self.logger.propagate = False  # 关键修复：禁止日志传播
            self._configure_handlers(logger_name)
        self.__class__._register_cleanup()

    @classmethod
    def _register_cleanup(cls):
        """注册程序退出时的清理检查"""
        atexit.register(cls._analyze_error_logs)

    @classmethod
    def _analyze_error_logs(cls):
        """分析错误日志并生成报告"""
        error_records = []

        # 遍历所有生成的日志文件
        for log_file in cls._generated_logs:
            if not log_file.exists():
                continue

            # 读取日志内容
            with open(log_file, 'r', encoding='utf-8') as f:
                for line in f:
                    if ' - ERROR - ' in line:
                        error_records.append({
                            'file': log_file.name,
                            'content': line.strip()
                        })

            # 清空已处理文件记录
            cls._generated_logs.remove(log_file)

        # 生成错误报告
        if error_records:
            report_dir = Path(__file__).parent.parent / 'logs'
            report_dir.mkdir(parents=True, exist_ok=True)
            report_path = report_dir / 'test_result.txt'

            # 写入报告内容
            with open(report_path, 'a', encoding='utf-8') as f:
                header = f"\n\n=== Error Report {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===\n"
                f.write(header)
                for record in error_records:
                    f.write(f"[File] {record['file']}\n")
                    f.write(f"[Error] {record['content']}\n")
                    f.write("-" * 50 + "\n")
            print(f"发现{len(error_records)}条错误日志，已保存至：{report_path}")

    @classmethod
    def _detect_root_script(cls):
        """增强的脚本检测方法"""
        # 方法1：检测测试框架
        test_script = cls._detect_test_script()
        if test_script:
            return test_script

        # 方法2：命令行参数检测
        if sys.argv and sys.argv[0]:
            try:
                path = Path(sys.argv[0])
                if path.stem not in ["pytest", "_jb_"]:
                    return path.stem
            except Exception:
                pass

        # 方法3：调用栈分析
        stack = inspect.stack()
        for frame_info in reversed(stack):
            filename = frame_info.filename
            if filename != __file__ and not filename.startswith("<"):
                path = Path(filename)
                if path.stem not in ["unittest", "pytest"]:
                    return path.stem
        return None

    @classmethod
    def _detect_test_script(cls):
        """深度检测测试脚本路径"""
        # 遍历调用栈寻找测试用例
        for frame_info in inspect.stack():
            frame = frame_info.frame
            # 查找测试用例实例
            for var_name, var_val in frame.f_locals.items():
                if isinstance(var_val, unittest.TestCase):
                    module = inspect.getmodule(var_val)
                    if module and hasattr(module, '__file__'):
                        file_path = module.__file__
                        if "site-packages" not in file_path:
                            return Path(file_path).stem
        return None

    def _configure_handlers(self, name):
        """重构的处理器配置方法"""
        # 统一使用配置参数
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - [%(funcName)s] - %(message)s'
        )

        # 创建日志目录
        base_log_path = Path(__file__).parent.parent / "logs"
        log_path = base_log_path / (self.device_type or "default")
        log_path.mkdir(parents=True, exist_ok=True)

        # 生成日志文件路径
        log_file = log_path / f"{name}.log"
        self.__class__._generated_logs.append(log_file)

        # 清理已有处理器（确保唯一性）
        self.logger.handlers.clear()

        # 文件处理器（始终添加）
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)

        # 控制台处理器（按配置添加）
        if self.config.enable_console_logging:
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(formatter)
            self.logger.addHandler(console_handler)

        # 日志轮转（按需添加）
        if self.config.enable_log_rotation:
            rotation_handler = RotatingFileHandler(
                log_file,
                maxBytes=self.config.log_max_bytes,
                backupCount=self.config.log_backup_count,
                encoding='utf-8'
            )
            rotation_handler.setFormatter(formatter)
            self.logger.addHandler(rotation_handler)


    def get_logger(self):
        return self.logger

def main_logger(device_type=None):
    return Logger(device_type=device_type).get_logger()